#include <iostream>
extern "C"
{
    #include <libavformat/avformat.h>
}
#include "MYDemux.h"
#include <QDebug>
using namespace std;

// 用于控制视频播放速度，使得跟音频同步
static double r2d(AVRational r)
{
    // num是分数，den是分母
    return r.den == 0 ? 0 : (double)r.num / (double)r.den;
}

MYDemux::MYDemux()
{
    static bool isFirst = true;
    static std::mutex dmux;
    dmux.lock();
    if(isFirst) {
        // 初始化封装库
        av_register_all();
        // 初始化网络库 （可以打开rtsp rtmp http 协议的流媒体视频）
        avformat_network_init();
        isFirst = false;
    }
    dmux.unlock();
}


// 清空读取缓存
void MYDemux::Clear()
{
    mux.lock();
    if(!context) {
        mux.unlock();
        return;
    }
    // 清理读取缓存（context内部的缓存）
    avformat_flush(context);
    mux.unlock();
}

void MYDemux::Close()
{
    mux.lock();
    if (!context) {
        mux.unlock();
        return;
    }
    // 关闭一个打开的容器，并释放资源
    avformat_close_input(&context);
    //媒体总时长（毫秒）
    totalMs = 0;
    mux.unlock();
}

// seek 位置 pos 0.0 ~1.0 百分数
// 用于跳转位置
bool MYDemux::Seek(double pos)
{
    mux.lock();
    if(!context) {
        mux.unlock();
        return false;
    }
    avformat_flush(context);

    long long seekPos = 0;
    // duration 是视频时长
    seekPos = context->streams[videoIdx]->duration * pos;
	qDebug() << "demux.seekPos:" << seekPos;
    // AVSEEK_FLAG_BACKWARD 从这个时间点往前找到第一帧可播放的图像
    // AVSEEK_FLAG_FRAME 使用帧数量
    int ret = av_seek_frame(context, videoIdx, seekPos, AVSEEK_FLAG_BACKWARD | AVSEEK_FLAG_FRAME);
    mux.unlock();
    if (ret < 0) return false;
    return true;
}

AVCodecParameters *MYDemux::CopyVPara()
{
    mux.lock();
    if (!context)
    {
        mux.unlock();
        return NULL;
    }
    AVCodecParameters *pa = avcodec_parameters_alloc();
    avcodec_parameters_copy(pa, context->streams[videoIdx]->codecpar);
    mux.unlock();
    return pa;
}

AVCodecParameters *MYDemux::CopyAPara()
{
    mux.lock();
    if (!context)
    {
        mux.unlock();
        return NULL;
    }
    AVCodecParameters *pa = avcodec_parameters_alloc();
    avcodec_parameters_copy(pa, context->streams[audioIdx]->codecpar);
    mux.unlock();
    return pa;
}

// 是音频返回true，其余返回false
bool MYDemux::IsAudio(AVPacket *pkt)
{
    if(!pkt) return false;
    if(pkt->stream_index == videoIdx) return false;
    return true;
}

// 只读视频，音频丢弃
AVPacket *MYDemux::ReadVideo()
{
    mux.lock();
    if(!context) {
        mux.unlock();
        return nullptr;
    }
    mux.unlock();
    AVPacket *pkt = nullptr;
    // 防止阻塞, 不读太多帧
    for(int i = 0; i < 20; ++i) {
        pkt = Read();
        if(!pkt) break;
        if(pkt->stream_index == videoIdx) break;
        av_packet_free(&pkt);
    }
    return pkt;
}

AVPacket *MYDemux::Read()
{
    mux.lock();
    if(!context) {
        mux.unlock();
        return nullptr;
    }

    AVPacket *pkt = av_packet_alloc();
    // 读取一帧pkt，并分配空间
    int ret = av_read_frame(context, pkt);
    if(ret != 0) {
        mux.unlock();
        av_packet_free(&pkt);
        return 0;
    }
    // pts 转换为 ms
    pkt->pts = pkt->pts * (1000 * (r2d(context->streams[pkt->stream_index]->time_base)));
    pkt->dts = pkt->dts * (1000 * (r2d(context->streams[pkt->stream_index]->time_base)));

    mux.unlock();
    //cout << pkt->pts << " "<<flush;
    return pkt;
}

// 打开视频文件
bool MYDemux::Open(const char *url)
{
    Close();
    // 参数设置
    AVDictionary *opts = nullptr;
    // 设置rtsp流打开tcp协议
    av_dict_set(&opts, "rstp_transport", "tcp", 0);

    // 网络延时时间
    av_dict_set(&opts, "max_delay", "500", 0);

    mux.lock();

    // 0表示自动选择解封器
    int ret = avformat_open_input(&context, url, 0, &opts);
    if(ret != 0) {
        mux.unlock();
        char buf[1024] = { 0 };
        av_strerror(ret, buf, sizeof(buf) - 1);
        cout << "open " << url << " failed! :" << buf << endl;
        return false;
    }
    cout << "open " << url << " success! " << endl;

    // 获取流信息
    ret = avformat_find_stream_info(context, 0);

    // 总时长 ms  duration 单位是us
    this->totalMs = context->duration / (AV_TIME_BASE / 1000);
    cout << "totalMs = " << totalMs << endl;

    // 打印视频流详细信息
    av_dump_format(context, 0, url, 0);


    // 获取视频流
    videoIdx = av_find_best_stream(context, AVMEDIA_TYPE_VIDEO, -1, -1, NULL, 0);
    AVStream *as = context->streams[videoIdx];
    width = as->codecpar->width;
    height = as->codecpar->height;

    cout << "======================================================================" << endl;
    cout << videoIdx << "视频信息" << endl;
    cout << "codec_id = " << as->codecpar->codec_id << endl;
    cout << "format = " << as->codecpar->format << endl;
    cout << "width=" << as->codecpar->width << endl;
    cout << "height=" << as->codecpar->height << endl;
    //帧率 fps 分数转换
    cout << "video fps = " << r2d(as->avg_frame_rate) << endl;

    cout << "======================================================================" << endl;
    cout << audioIdx << "音频信息" << endl;

    // 获取音频流
    audioIdx = av_find_best_stream(context, AVMEDIA_TYPE_AUDIO, -1, -1, NULL, 0);
    as = context->streams[audioIdx];
    sampleRate = as->codecpar->sample_rate;
    channels = as->codecpar->channels;

    cout << "codec_id = " << as->codecpar->codec_id << endl;
    cout << "format = " << as->codecpar->format << endl;
    cout << "sample_rate = " << as->codecpar->sample_rate << endl;
    // AVSampleFormat
    cout << "channels = " << as->codecpar->channels << endl;
    // 一帧数据：存放一定量样本数
    cout << "frame_size = " << as->codecpar->frame_size << endl;
    //fps = sample_rate/frame_size
    mux.unlock();

    return true;
}

MYDemux::~MYDemux()
{

}
